package com.example.venue_reservation_service.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.venue_reservation_service.domain.*;
import com.example.venue_reservation_service.dto.PageDTO;
import com.example.venue_reservation_service.dto.SQueryDTO;
import com.example.venue_reservation_service.dto.UserDTO;
import com.example.venue_reservation_service.mapper.*;
import com.example.venue_reservation_service.service.*;
import com.example.venue_reservation_service.vo.*;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;

/**
* @author 31586
* @description 针对表【venue_slot(管理员禁用场地记录表)】的数据库操作Service实现
* @createDate 2024-12-23 18:34:08
*/
@Service
public class SlotServiceImpl extends ServiceImpl<SlotMapper, Slot>
    implements SlotService {

    @Resource
    private InformationService informationService;

    @Resource
    private ReservationMapper reservationMapper;

    @Resource
    private TypeService typeService;

    @Resource
    private VenueSlotMapper venueSlotMapper;

    @Resource
    private AdminMapper adminMapper;

    @Resource
    private UserMapper userMapper;


    @Override
    public Result getStatus(SQueryDTO dto) {

        LocalDate reservationDate = dto.getReservationDate();
        Integer venueId = dto.getVenueId();

        // 查看已经签到的
        QueryWrapper<Reservation> signWrapper = new QueryWrapper<>();
        signWrapper.select("DISTINCT time_id")
                .eq("reservation_date", reservationDate)
                .eq("venue_id", venueId)
                .eq("audit_status", 1);

        List<Integer> signIds = reservationMapper.selectObjs(signWrapper)
                .stream()
                .map(obj -> (Integer) obj).toList();

        // 查看被预约的
        QueryWrapper<Reservation> reservationWrapper = new QueryWrapper<>();
        reservationWrapper.select("DISTINCT time_id")
                .eq("reservation_date", dto.getReservationDate())
                .eq("venue_id", dto.getVenueId())
                .eq("audit_status", 1);

        List<Integer> reservationIds = reservationMapper.selectObjs(reservationWrapper)
                .stream()
                .map(obj -> (Integer) obj).toList();


        List<CancelVO> list = new ArrayList<>();
        for (Slot slot : list(Wrappers.<Slot>lambdaQuery()
                .eq(Slot::getReservationDate, reservationDate))
//                .eq(Slot::getVenueId, venueId))
        ) {
            list.add(BeanUtil.copyProperties(slot, CancelVO.class));
        }
        return Result.ok(new SlotTime(signIds, reservationIds, list)).message("ok");
    }

    @Override
    public Result querySlots(UserDTO dto) {
        Page<Slot> page = new Page<>(dto.getCurrent(), dto.getSize());
        List<Slot> list = page(page, Wrappers.<Slot>lambdaQuery()
                .eq(Slot::getUserId, dto.getUserId())
                .eq(Slot::getReservationDate, dto.getDate())
                .orderByAsc(Slot::getReservationDate))
                .getRecords();
        List<SlotItem> result = new ArrayList<>();
        for (Slot slot : list) {
            // 加载场地信息
            LambdaQueryWrapper<VenueSlot> wrapper = Wrappers.<VenueSlot>lambdaQuery();
            wrapper.select(VenueSlot::getVenueId)
                    .eq(VenueSlot::getSlotId, slot.getId());
            List<Integer> vids = venueSlotMapper.selectObjs(wrapper)
                    .stream()
                    .map(obj -> (Integer) obj)
                    .toList();
            List<Information> information = informationService.list(Wrappers.<Information>lambdaQuery()
                    .in(Information::getId, vids));
            result.add(new SlotItem(slot, information));
        }
        return Result.ok(result).message("ok");
    }

    @Override
    public Result delSlot(Integer slotId, Integer userId) {
        Slot slot = getById(slotId);
        if (Optional.ofNullable(slot).isEmpty()) {
            return Result.fail().message("未查询到禁用信息");
        }
        // 校验用户是否有权限
        User user = userMapper.selectById(userId);
        if (Optional.ofNullable(user).isEmpty()) {
            return Result.fail().message("用户信息不存在");
        }
        if (user.getType() != 4 && slot.getUserId() != userId) {
            return Result.fail().message("无权限删除");
        }

        LocalDate reservationDate = slot.getReservationDate();
        int compareTo = reservationDate.compareTo(LocalDate.now());
        if (compareTo == 0) {
            // 今天的，判断时间段是否合理
            LocalTime start = slot.getSlotStart();
            LocalTime end = slot.getSlotEnd();
            LocalTime now = LocalTime.now();
            if(now.isBefore(end) && now.isAfter(start)){
                return Result.fail().message("移除失败，禁用已经生效");
            }
//            if(now.isAfter(end)) return Result.fail().message("禁用已经过期");
        }
        // 移除关联信息
        venueSlotMapper.delete(Wrappers.<VenueSlot>lambdaQuery()
                .eq(VenueSlot::getSlotId, slot.getId()));
        removeById(slotId);
        return Result.ok().message("移除成功");
    }

    @Override
    public Result pageSlots(PageDTO dto) {
        Page<Slot> page = new Page<>(dto.getCurrent(), dto.getSize());
        page = page(page, Wrappers.<Slot>lambdaQuery().orderByDesc(Slot::getAddTime));
        List<Slot> records = page.getRecords();
        List<SlotVO> res = new ArrayList<>();
        records.forEach(item -> {
            SlotVO vo = BeanUtil.copyProperties(item, SlotVO.class);
            User user = userMapper.selectById(item.getUserId());
            if (Optional.ofNullable(user).isEmpty()) {
                vo.setUsername("未查询到管理员信息");
            }else{
                if(user.getType() == 4){
                    vo.setUsername("超级管理员");
                }else {
                    Admin admin = adminMapper.selectOne(Wrappers.<Admin>lambdaQuery()
                            .eq(Admin::getUserId, user.getId()));
                    if (Optional.ofNullable(admin).isEmpty()) {
                        vo.setUsername("管理员（"+"***)");
                    }else {
                        String venueName = typeService.getById(admin.getTypeId()).getVname();
                        vo.setUsername("管理员（"+venueName+"）");
                    }
                }
            }
            res.add(vo);
        });
        return Result.ok(new QueryVO<>(res, page.getTotal())).message("query success");
    }

    @Override
    public Result slotVenues(Integer id) {
        List<SlotResult> list = new ArrayList<>();
        // 获取所有场馆信息
        for (Type type : typeService.list()) {
            SlotResult slotResult = new SlotResult();
            slotResult.setVName(type.getVname());

            // 加载这个时间段下
            List<VenueSlot> venueSlots = venueSlotMapper.selectList(Wrappers.<VenueSlot>lambdaQuery().eq(VenueSlot::getSlotId, id));
            List<Integer> venueIds = new ArrayList<>();
            for (VenueSlot venueSlot : venueSlots) {
                venueIds.add(venueSlot.getVenueId());
            }

            // 查询场地数据
            LambdaQueryWrapper<Information> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Information::getTypeId, type.getId());
            if (venueIds.size() > 0){
                wrapper.notIn(Information::getId, venueIds);
            }

            for (Information information : informationService.list(wrapper)) {
                slotResult.getList().add(BeanUtil.copyProperties(information, VenueResult.class));
            }
            list.add(slotResult);
        }
        return Result.ok(list).message("query success");
    }

    /**
     * 校验时间
     * @param slot
     * @return
     */
    private boolean isEffective(Slot slot){
        // 如果是移除当天的禁用场地，需要判断是否有效
        LocalTime start = slot.getSlotStart();
        LocalTime slotEnd = slot.getSlotEnd();
        if(start.isBefore(LocalTime.now()) && slotEnd.isAfter(LocalTime.now())){
            return true;
        }
        return false;
    }

    @Override
    public Result createSlot(Slot slot) {
        // 判断是否已有此时间段
        Slot one = getOne(Wrappers.<Slot>lambdaQuery()
                .eq(Slot::getReservationDate, slot.getReservationDate())
                .eq(Slot::getSlotStart, slot.getSlotStart())
                .eq(Slot::getSlotEnd, slot.getSlotEnd()));
        if (Optional.ofNullable(one).isPresent()) {
            return Result.fail().message("禁用信息已存在");
        }

        // 判断时间段是否有效
        int compareTo = LocalDate.now().compareTo(slot.getReservationDate());
        if (compareTo>0) {
            // 过去的
            return Result.fail().message("禁用日期不能设置为过去的日期");
        } else if (compareTo == 0) {
            // 现在
            if (isEffective(slot)) {
                return Result.fail().message("非法时间段");
            }
            if(slot.getSlotEnd().isBefore(LocalTime.now())){
                return Result.fail().message("无效禁用时间");

            }
        }
        slot.setAddTime(LocalDateTime.now());
        save(slot);
        return Result.ok().message("ok");
    }

    /**
     * 设置当前禁用时间下的场地信息
     * @param venueIds
     * @param slotId
     * @return
     */
    @Override
    public Result setSlots(List<Integer> venueIds, Integer slotId) {
        // 获取禁用时间段
        Slot slot = getById(slotId);
        if(Optional.ofNullable(slot).isEmpty()){
            return Result.fail().message("禁用时段不存在");
        }
        List<Reservation> reservations = reservationMapper.selectList(Wrappers.<Reservation>lambdaQuery()
                .in(Reservation::getVenueId, venueIds)
                .in(Reservation::getAuditStatus, 1, 2)
                .eq(Reservation::getReservationDate, slot.getReservationDate())
                .lt(Reservation::getStartTime, slot.getSlotEnd())
                .gt(Reservation::getEndTime, slot.getSlotStart()));
        if (reservations.size() > 0) {
            return Result.fail().message("部分场地已被预约");
        }
        // 批量绑定场地信息
        for (Integer venueId : venueIds) {
            VenueSlot vs = new VenueSlot();
            vs.setSlotId(slotId);
            vs.setVenueId(venueId);
            venueSlotMapper.insert(vs);
        }
        return Result.ok().message("场地信息绑定成功");
    }

    @Override
    public Result inquireMsg(Integer slotId) {
        LambdaQueryWrapper<VenueSlot> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(VenueSlot::getVenueId)
                .eq(VenueSlot::getSlotId, slotId);
        List<Integer> list = venueSlotMapper.selectObjs(wrapper).stream().map(obj -> (Integer) obj).toList();
        List<VenueResult> results = new ArrayList<>();
        if (list.size() == 0) {
            return Result.ok(results).message("ok");
        }
        informationService.list(Wrappers.<Information>lambdaQuery()
                .in(Information::getId, list)).forEach(item -> {
                   String str = item.getVenueName();
            VenueResult result = new VenueResult();
            result.setId(item.getId());
            Type type = typeService.getById(item.getTypeId());
            if (Optional.ofNullable(type).isPresent()) {
                str+=" - ("+type.getVname()+")";
            }else {
                str+=" - (***)";
            }
            result.setVenueName(str);
            results.add(result);
        });
        return Result.ok(results).message("ok");
    }

    @Override
    public Result removeSlot(Integer vId, Integer sId) {
        // 进行逻辑判断
        Slot slot = getById(sId);
        if (LocalDate.now().compareTo(slot.getReservationDate()) ==0) {
            // 如果是移除当天的禁用场地，需要判断是否有效
            if (isEffective(slot)) {
                // 如果不存在场地数据
                if (venueSlotMapper.selectList(Wrappers.<VenueSlot>lambdaQuery().eq(VenueSlot::getSlotId, sId)).size() == 0) {
                    // 删除时间段数据
                    removeById(sId);
                    return Result.ok().message("ok");
                }
                return Result.fail().message("已生效");
            }
        }
        // 如果 vId = -1 表示全部移除
        LambdaQueryWrapper<VenueSlot> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(VenueSlot::getSlotId,sId);
        if(vId != -1){
            wrapper.eq(VenueSlot::getVenueId, vId);
        }
        venueSlotMapper.delete(wrapper);
        // 删除时间段数据
        if(vId == -1){
            removeById(sId);
        }
        return Result.ok().message("ok");
    }


}




